import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.IntBuffer;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.glu.GLU;

import com.sun.opengl.util.GLUT;

public class Sockets {
	private GLU glu;
	private GLUT glut;
	public boolean ready;
	public ServerSocket ss;
	public Socket socket;
	char[] output_buffer,buffer;
	private int s_width, s_height;
	InputStream sin;
	OutputStream sout;
	DataInputStream in;
	DataOutputStream out;
	BufferedReader keyboard;
	private String client_data,server_data;
	private int port;//socket port
	public boolean connection;//to server or by client
	public boolean server;//server or client?
	public boolean but_1, but_2;//1, 2 pressed?
	private boolean drawed;//for waiting prompter
	
	public Sockets(GL _gl,GLU _glu, GLUT _glut) {
		glu = _glu;
		glut = _glut;
		output_buffer = new char[7];
		buffer = new char[100];
		init();
	}
	public void clear() {
		System.out.println(server);
		if(server)
			try {
				ss.close();
			} catch (IOException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			}
		ss = null;
		try {
			in.close();
		} catch (IOException e1) {
			System.out.println("Error closing buffers");
		}
		in = null;
		try {
			out.close();
		} catch (IOException e1) {
			System.out.println("Error closing buffers");
		}
		out = null;
		try {
			socket.close();
		} catch (IOException e) {
		System.out.println("Error closing socket");
		}
		socket = null;
		try {
			sin.close();
		} catch (IOException e) {
			System.out.println("Error closing buffers");
		}
		sin = null;
		try {
			sout.close();
		} catch (IOException e) {
			System.out.println("Error closing buffers");
		}
		sout = null;
	}
	private void init() {
		ready = false;
		connection = false;
    	but_1 = false;
    	but_2 = false;
    	drawed = false;
    	port = 1488;
	}
	private void init_buffers() {
		try {
			sin = socket.getInputStream();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			sout = socket.getOutputStream();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		server_data = new String();
		client_data = new String();
		server_data = "\0";
		client_data = "\0";
		in = new DataInputStream(sin);
		out = new DataOutputStream(sout);
		keyboard = new BufferedReader(new InputStreamReader(System.in));
	}
	private void set_server(GLAutoDrawable drawable) {
		but_1 = false;
		try {
			ss = new ServerSocket(port);
			socket = ss.accept();
			server = true;
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			drawed = false;
			return;
		}
		connection = true;
		init_buffers();
	}
	private void set_client(GLAutoDrawable drawable,char[] _buffer) {
		but_2 = false;
		ready = false;
		String address = new String(_buffer);
		try {
			InetAddress ipAddress = InetAddress.getByName(address);
			try {
				socket = new Socket(ipAddress, port);
				server = false;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				drawed = false;
				return;
			}
			
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			drawed = false;
			return;
		}
		connection = true;
		init_buffers();
	}
	public void do_something() {
		
	}
	private void draw(GLAutoDrawable drawable,String data,boolean who,boolean read) {
		if(data == null) return;
		final GL gl = drawable.getGL();
		char string[] = new char[110];
	        //Assume we are in MODEL_VIEW already
		gl.glPushMatrix();
		gl.glLoadIdentity();
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glPushMatrix();
		gl.glLoadIdentity();
		java.nio.IntBuffer viewport;
		viewport = IntBuffer.allocate(4);
		gl.glGetIntegerv(GL.GL_VIEWPORT, viewport);
		int view[] = new int[4];
		view = viewport.array();
		glu.gluOrtho2D(0,view[2],view[3],0);
		gl.glDepthFunc(GL.GL_ALWAYS);
		if(who) gl.glColor3f (1,0,0);
		else gl.glColor3f (0,1,0);
		int i = 0;
	//	System.out.println((int)data.charAt(0));
		if(data.charAt(0) != '\0') {
			
		//	if(read) System.out.println("read data: " + (int)data.charAt(0)+ " " + (int)data.charAt(1)+ " " + (int)data.charAt(2) + " "+ (int)data.charAt(3)+ " "  + (int)data.charAt(4));
		//	else System.out.println("write data: " + (int)data.charAt(0)+ " " + (int)data.charAt(1)+ " " + (int)data.charAt(2) + " "+ (int)data.charAt(3)+ " "  + (int)data.charAt(4));
			if(read) { 
				if(data.charAt(3) == '1') {
			
				MyJoglCanvas.start_firing = true;
				MyJoglCanvas.target.x = data.charAt(0); 
				MyJoglCanvas.target.y = data.charAt(1);
				MyJoglCanvas.target.z = data.charAt(2);
			}
			else MyJoglCanvas.start_firing = false;
			if(data.charAt(4) == '1') MyJoglCanvas.enemy_ready = true;
			if(data.charAt(5) == '0') MyJoglCanvas.enemy_shooting_result = 0;
			else if(data.charAt(5) == '1') MyJoglCanvas.enemy_shooting_result = 1;
			else if(data.charAt(5) == '2') MyJoglCanvas.enemy_shooting_result = 2;
			if(data.charAt(6) == '0') MyJoglCanvas.enemy_terminated = 0;
			else if(data.charAt(6) == '1') MyJoglCanvas.enemy_terminated = 1;
			}
			
		if(who && data.charAt(7) != '\0') {
			string[0] = 'S';
			string[1] = 'e';
			string[2] = 'r';
			string[3] = 'v';
			string[4] = 'e';
			string[5] = 'r';
			string[6] = ':';
			string[7] = ' ';
			i = 8;
		}
		else if(!who && data.charAt(7) != '\0'){
			string[0] = 'C';
			string[1] = 'l';
			string[2] = 'i';
			string[3] = 'e';
			string[4] = 'n';
			string[5] = 't';
			string[6] = ':';
			string[7] = ' ';
			i = 8;
		}
		int val = 0;
		for(; i < 110; i++) {
			string[i] = data.charAt(i-val);
			if(string[i] == '\n' || string[i] == '\0') {
				string[i] = '\0';
				break;
			}
		}
		if(who) gl.glRasterPos2f(20, s_height/2 - 10);
		else gl.glRasterPos2f(20, s_height/2 + 10);
		for (i = 8; string[i]!= '\0'; ++i)
	    glut.glutBitmapCharacter(GLUT.BITMAP_HELVETICA_18, string[i]);
		}
		gl.glDepthFunc(GL.GL_LESS);
		gl.glPopMatrix();
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glPopMatrix();
		gl.glColor3f (1,0,0);
		
	}
	public void writeMessage(GLAutoDrawable drawable,boolean read,char[] _buffer) throws IOException {
		if(read) for(int i = 0; i< 100; i++) buffer[i] = _buffer[i];
		output_buffer[0] = '1';
		output_buffer[1] = '1';
		output_buffer[2] = '1';
		if(MyJoglCanvas.shooting_result == 0)output_buffer[5] = '0';
		else if(MyJoglCanvas.shooting_result == 1)output_buffer[5] = '1';
		else output_buffer[5] = '2';
		
		if(MyJoglCanvas.terminated == 0)output_buffer[6] = '0';
		else if(MyJoglCanvas.terminated == 1)output_buffer[6] = '1';

		if(MyJoglCanvas.ready_for_war) {
			output_buffer[4] = '1';
		}
		else output_buffer[4] = '2';
		if(MyJoglCanvas.start_firing) { 
			output_buffer[3] = '1';
			output_buffer[0] = (char)((int)MyJoglCanvas.target.x());
			output_buffer[1] = (char)((int)MyJoglCanvas.target.y());
			output_buffer[2] = (char)((int)MyJoglCanvas.target.z());
		}
		else output_buffer[3] = '2';
		
		if(server) {
				client_data = in.readUTF();
				draw(drawable,client_data,false,true);//true = server data, false - client
				server_data = new String(output_buffer);
				server_data += new String(buffer);
				server_data += new String("\0");
					//server_data.concat(output_buffer.toString());
				out.writeUTF(server_data);	
				out.flush();
				draw(drawable,server_data,true,false);
		}
		else  {
				client_data = new String(output_buffer);
				client_data += new String(buffer);
				client_data += new String("\0");
					//client_data.concat(output_buffer.toString());
						
				out.writeUTF(client_data);	
				out.flush();
				draw(drawable,client_data,false,false);
				server_data = in.readUTF();
				draw(drawable,server_data,true,true);
		}
		server_data = null;
		client_data = null;
		for(int i = 0; i < 6; i++) output_buffer[i] = 0;
	}
	private void connecting(GLAutoDrawable drawable) {//drawing prompter
		drawed = true;
		final GL gl = drawable.getGL();
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		String quest = new String(); 
		quest = "Connecting to server...\n";
		char string[] = new char[100];
	        //Assume we are in MODEL_VIEW already
		gl.glPushMatrix();
		gl.glLoadIdentity();
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glPushMatrix();
		gl.glLoadIdentity();
		java.nio.IntBuffer viewport;
		viewport = IntBuffer.allocate(4);
		gl.glGetIntegerv(GL.GL_VIEWPORT, viewport);
		int view[] = new int[4];
		view = viewport.array();
		glu.gluOrtho2D(0,view[2],view[3],0);
		gl.glDepthFunc(GL.GL_ALWAYS);
		gl.glColor3f (1,1,1);
		for(int i = 0; i < 100; i++) {
			string[i] = quest.charAt(i);
			if(string[i] == '\n') {
				string[i] = '\0';
				break;
			}
		}
		gl.glRasterPos2f(s_width/2 - 10, s_height/2 - 10);
		for (int i = 0; string[i]!= '\0'; ++i)
	    glut.glutBitmapCharacter(GLUT.BITMAP_HELVETICA_18, string[i]);
		gl.glDepthFunc(GL.GL_LESS);
		gl.glPopMatrix();
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glPopMatrix();
	}
	private void waiting(GLAutoDrawable drawable) {//drawing prompter
		drawed = true;
		final GL gl = drawable.getGL();
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		String quest = new String(); 
		quest = "Waiting for a client...\n";
		char string[] = new char[100];
	        //Assume we are in MODEL_VIEW already
		gl.glPushMatrix();
		gl.glLoadIdentity();
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glPushMatrix();
		gl.glLoadIdentity();
		java.nio.IntBuffer viewport;
		viewport = IntBuffer.allocate(4);
		gl.glGetIntegerv(GL.GL_VIEWPORT, viewport);
		int view[] = new int[4];
		view = viewport.array();
		glu.gluOrtho2D(0,view[2],view[3],0);
		gl.glDepthFunc(GL.GL_ALWAYS);
		gl.glColor3f (1,1,1);
		for(int i = 0; i < 100; i++) {
			string[i] = quest.charAt(i);
			if(string[i] == '\n') {
				string[i] = '\0';
				break;
			}
		}
		gl.glRasterPos2f(s_width/2 - 10, s_height/2 - 10);
		for (int i = 0; string[i]!= '\0'; ++i)
	    glut.glutBitmapCharacter(GLUT.BITMAP_HELVETICA_18, string[i]);
		gl.glDepthFunc(GL.GL_LESS);
		gl.glPopMatrix();
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glPopMatrix();
	}
	private void question(GLAutoDrawable drawable) {//drawing question
		drawed = false;
		final GL gl = drawable.getGL();
		String quest = new String(); 
		quest = "Press \"1\" to start new game\n";
		char string[] = new char[100];
	        //Assume we are in MODEL_VIEW already
		gl.glPushMatrix();
		gl.glLoadIdentity();
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glPushMatrix();
		gl.glLoadIdentity();
		java.nio.IntBuffer viewport;
		viewport = IntBuffer.allocate(4);
		gl.glGetIntegerv(GL.GL_VIEWPORT, viewport);
		int view[] = new int[4];
		view = viewport.array();
		glu.gluOrtho2D(0,view[2],view[3],0);
		gl.glDepthFunc(GL.GL_ALWAYS);
		gl.glColor3f (1,1,1);
		for(int i = 0; i < 100; i++) {
			string[i] = quest.charAt(i);
			if(string[i] == '\n') {
				string[i] = '\0';
				break;
			}
		}
		quest = "Press \"2\" to connect to server\n";
		gl.glRasterPos2f(20, s_height/2 - 10);
		for (int i = 0; string[i]!= '\0'; ++i)
	    glut.glutBitmapCharacter(GLUT.BITMAP_HELVETICA_18, string[i]);
		for(int i = 0; i < 100; i++) {
			string[i] = quest.charAt(i);
			if(string[i] == '\n') {
				string[i] = '\0';
				break;
			}
		}
		quest = "Press \"3\" to run game in a developer mode\n";
		gl.glRasterPos2f(20, s_height/2 + 10);
		for (int i = 0; string[i]!= '\0'; ++i)
	    glut.glutBitmapCharacter(GLUT.BITMAP_HELVETICA_18, string[i]);
		for(int i = 0; i < 100; i++) {
			string[i] = quest.charAt(i);
			if(string[i] == '\n') {
				string[i] = '\0';
				break;
			}
		}
		gl.glRasterPos2f(20, s_height/2 + 30);
		for (int i = 0; string[i]!= '\0'; ++i)
	    glut.glutBitmapCharacter(GLUT.BITMAP_HELVETICA_18, string[i]);
		gl.glDepthFunc(GL.GL_LESS);
		gl.glPopMatrix();
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glPopMatrix();
	}
	public void choose_mode(GLAutoDrawable drawable,int width, int height, char[] buffer) {
		    s_width = width;
		    s_height = height;
			if(but_1 && !drawed) {
	    	   waiting(drawable);//рисовалки опознавательные при ожидании клиента
	    	   return;
	        }
			else if(but_2 && !drawed) {
				connecting(drawable);//рисовалки опознавательные при попытке подключения
				return;
			}
		   if(but_1) {
			   set_server(drawable);//сервер создается сразу после выбора сервера без лишних проверок
			   waiting(drawable);
			   return;
		   }
		   else if(but_2 && ready) {
			   set_client(drawable,buffer);//попытка подключения к серверу только после заполнения буфера с айпи
			   connecting(drawable);
			   return;
		   }
		   else if(!but_2 && !but_1)question(drawable);
	}
}